#include "apue.h"
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

#define F_E_NOEXIST 2
#define PER_READ 1024

static int exist(const char *filepath);

int main(int argc, char *argv[]) {
    int fd1, fd2, eno;
    char * tarname, * l_slash;
    int c, i, r_c;
    char buf[PER_READ], wbuf[PER_READ];

    struct stat st;
    if (argc != 3) 
        err_quit("cp <src-file> <tar-file>");
    
    if (strcmp(argv[1], argv[2]) == 0)
        err_quit("cp: '%s' and '%s' are the same file", argv[1], argv[2]);

    if (stat(argv[1], &st) < 0)
        err_sys("stat file %s failed", argv[1]);

    if (S_ISDIR(st.st_mode) != 0)
        err_quit("Sorry, I cant copy directory");

    if ((fd1= open(argv[1], O_RDONLY)) < 0)
        err_sys("open file failed");

    eno= errno= 0;
    if (stat(argv[2], &st) < 0 && (eno = errno) != F_E_NOEXIST)
        err_sys("stat %s failed", argv[2]);

    // stat tar-file success, and tar-file should be directory 
    if (eno == 0) {
        if (S_ISDIR(st.st_mode) == 0)
            err_quit("target file %s had exist.");
        else {
            l_slash= strrchr(argv[1], '/');
            tarname= path_alloc(NULL);
            strcpy(tarname, argv[2]);
            if (argv[2][strlen(argv[2]) - 1] != '/')
                strcat(tarname, "/");
            strcat(tarname, l_slash == NULL ? argv[1] : l_slash+1);
        }

    } else 
        tarname= argv[2];   /* file not exist */

    if ((fd2= open(tarname, O_WRONLY | O_CREAT | O_EXCL, FILE_MODE)) < 0)
        err_sys("open file %s failed", tarname);

    while ((c= read(fd1, buf, PER_READ)) > 0) {
        if (c < 0)
            err_sys("read error");

        for (r_c=0, i=0; i<c; ++i) {
            if (buf[i] != '\0')
                wbuf[r_c++]= buf[i];
        }
        write(fd2, wbuf, r_c);
    }

}

static int exist(const char *filepath) {
    int eno;
    struct stat st;
    eno= errno= 0;
    if (stat(filepath, &st) < 0 && (eno = errno) != F_E_NOEXIST)
        err_sys("stat %s failed", filepath);

    return eno == 0;
}
